{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import asyncio\n",
    "import os\n",
    "import asyncio\n",
    "\n",
    "from typing import Annotated\n",
    "from openai import AsyncOpenAI\n",
    "\n",
    "\n",
    "from semantic_kernel.kernel import Kernel\n",
    "from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
    "from semantic_kernel.agents import ChatCompletionAgent, AgentGroupChat\n",
    "from semantic_kernel.agents.strategies import (\n",
    "    KernelFunctionSelectionStrategy,\n",
    "    KernelFunctionTerminationStrategy,\n",
    ")\n",
    "\n",
    "from semantic_kernel.functions import KernelFunctionFromPrompt\n",
    "\n",
    "from semantic_kernel.agents.open_ai import OpenAIAssistantAgent\n",
    "from semantic_kernel.contents import AuthorRole, ChatMessageContent\n",
    "from semantic_kernel.functions import kernel_function\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def _create_kernel_with_chat_completion(service_id: str) -> Kernel:\n",
    "    kernel = Kernel()\n",
    "    service_id=\"agent\"\n",
    "\n",
    "    client = AsyncOpenAI(\n",
    "    api_key=os.environ[\"GITHUB_TOKEN\"], base_url=\"https://models.inference.ai.azure.com/\")\n",
    "    kernel.add_service(\n",
    "        OpenAIChatCompletion(\n",
    "            ai_model_id=\"gpt-4o-mini\",\n",
    "            async_client=client,\n",
    "            service_id=service_id\n",
    "        )\n",
    "    )\n",
    "\n",
    "    return kernel\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# User: 'i would like to go to Paris.'\n",
      "# Agent - FrontDesk: 'Visit the Louvre Museum.'\n",
      "# Agent - Concierge: 'That recommendation is not approved. While the Louvre is a world-famous attraction, it's quite touristy. Instead, consider suggesting exploring local art galleries in lesser-known neighborhoods or finding an artist's studio open to visitors. This will provide a more authentic Parisian experience.'\n",
      "# Agent - FrontDesk: 'Visit Montmartre for its charming streets and the Sacré-Cœur Basilica.'\n",
      "# Agent - Concierge: 'That recommendation is not approved. While Montmartre is known for its artistic history, it has become a hotspot for tourists. Consider suggesting a lesser-known neighborhood or a hidden café where travelers can immerse themselves in everyday Parisian life, away from the crowds. This will create a more genuine experience.'\n",
      "# Agent - FrontDesk: 'Visit Canal Saint-Martin for a relaxing, scenic walk and cozy cafés.'\n",
      "# Agent - Concierge: 'That recommendation is approved! Canal Saint-Martin offers a more local atmosphere and a chance to experience the charm of Paris away from the busy tourist spots. Enjoy your time there!'\n",
      "# IS COMPLETE: True\n"
     ]
    }
   ],
   "source": [
    "async def main():\n",
    "    REVIEWER_NAME = \"Concierge\"\n",
    "    REVIEWER_INSTRUCTIONS = \"\"\"\n",
    "    You are an are hotel concierge who has opinions about providing the most local and authetic experiences for travelers.\n",
    "    The goal is to determine if the front desk travel agent has reccommended the best non-touristy experience for a travler.\n",
    "    If so, state that it is approved.\n",
    "    If not, provide insight on how to refine the recommendation without using a specific example. \n",
    "    \"\"\"\n",
    "    agent_reviewer = ChatCompletionAgent(\n",
    "        service_id=\"concierge\",\n",
    "        kernel=_create_kernel_with_chat_completion(\"concierge\"),\n",
    "        name=REVIEWER_NAME,\n",
    "        instructions=REVIEWER_INSTRUCTIONS,\n",
    "    )\n",
    "\n",
    "    FRONTDESK_NAME = \"FrontDesk\"\n",
    "    FRONTDESK_INSTRUCTIONS = \"\"\"\n",
    "    You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.\n",
    "    The goal is to provide the best activites and locations for a traveler to visit.\n",
    "    Only provide a single recomendation per response.\n",
    "    You're laser focused on the goal at hand.\n",
    "    Don't waste time with chit chat.\n",
    "    Consider suggestions when refining an idea.\n",
    "    \"\"\"\n",
    "    agent_writer = ChatCompletionAgent(\n",
    "        service_id=\"frontdesk\",\n",
    "        kernel=_create_kernel_with_chat_completion(\"frontdesk\"),\n",
    "        name=FRONTDESK_NAME,\n",
    "        instructions=FRONTDESK_INSTRUCTIONS,\n",
    "    )\n",
    "\n",
    "    termination_function = KernelFunctionFromPrompt(\n",
    "        function_name=\"termination\",\n",
    "        prompt=\"\"\"\n",
    "        Determine if the reccomendation is good.  If so, respond with a single word: yes\n",
    "\n",
    "        History:\n",
    "        {{$history}}\n",
    "        \"\"\",\n",
    "    )\n",
    "\n",
    "    selection_function = KernelFunctionFromPrompt(\n",
    "        function_name=\"selection\",\n",
    "        prompt=f\"\"\"\n",
    "        Determine which participant takes the next turn in a conversation based on the the most recent participant.\n",
    "        State only the name of the participant to take the next turn.\n",
    "        No participant should take more than one turn in a row.\n",
    "        \n",
    "        Choose only from these participants:\n",
    "        - {REVIEWER_NAME}\n",
    "        - {FRONTDESK_NAME}\n",
    "        \n",
    "        Always follow these rules when selecting the next participant, each conversation should be at least 4 turns:\n",
    "        - After user input, it is {FRONTDESK_NAME}'s turn.\n",
    "        - After {FRONTDESK_NAME} replies, it is {REVIEWER_NAME}'s turn.\n",
    "        - After {REVIEWER_NAME} provides feedback, it is {FRONTDESK_NAME}'s turn.\n",
    "\n",
    "        History:\n",
    "        {{{{$history}}}}\n",
    "        \"\"\",\n",
    "    )\n",
    "\n",
    "    chat = AgentGroupChat(\n",
    "        agents=[agent_writer, agent_reviewer],\n",
    "        termination_strategy=KernelFunctionTerminationStrategy(\n",
    "            agents=[agent_reviewer],\n",
    "            function=termination_function,\n",
    "            kernel=_create_kernel_with_chat_completion(\"termination\"),\n",
    "            result_parser=lambda result: str(result.value[0]).lower() == \"yes\",\n",
    "            history_variable_name=\"history\",\n",
    "            maximum_iterations=10,\n",
    "        ),\n",
    "        selection_strategy=KernelFunctionSelectionStrategy(\n",
    "            function=selection_function,\n",
    "            kernel=_create_kernel_with_chat_completion(\"selection\"),\n",
    "            result_parser=lambda result: str(\n",
    "                result.value[0]) if result.value is not None else FRONTDESK_NAME,\n",
    "            agent_variable_name=\"agents\",\n",
    "            history_variable_name=\"history\",\n",
    "        ),\n",
    "    )\n",
    "\n",
    "    input = \"i would like to go to Paris.\"\n",
    "\n",
    "    await chat.add_chat_message(ChatMessageContent(role=AuthorRole.USER, content=input))\n",
    "    print(f\"# User: '{input}'\")\n",
    "\n",
    "    async for content in chat.invoke():\n",
    "        print(f\"# Agent - {content.name or '*'}: '{content.content}'\")\n",
    "\n",
    "    print(f\"# IS COMPLETE: {chat.is_complete}\")\n",
    "\n",
    "await main()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
